package com.dxl.service.account;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dxl.bean.account.FunctionNode;
import com.dxl.common.enums.State;
import com.dxl.common.model.Order;
import com.dxl.common.model.Page;
import com.dxl.common.model.RespData;
import com.dxl.common.model.easyui.TreeNode;
import com.dxl.common.utils.Utils;
import com.dxl.dao.account.FunctionDao;
import com.dxl.entity.account.Function;
import com.dxl.entity.account.RoleFunction;
import com.dxl.service.common.BaseService;

@Service


public class FunctionService extends BaseService {
	private static final Logger LOG = Logger.getLogger(FunctionService.class);
	@Autowired
	private RoleService roleService;
	@Autowired
	private FunctionDao dao;
	
	public Page<Function> list(String parentId, String keyword, Integer state, Integer pageNo, Integer pageSize) {
		if (Utils.isBlank(parentId)) {
			return this.dao.list(null, keyword, state, pageNo, pageSize);
		} else {
			Set<String> childIds = listChildIds(parentId);
			childIds.add(parentId);
			return this.dao.list(childIds.toArray(new String[0]), keyword, state, pageNo, pageSize);
		}
	}
	
	public RespData save(Function function) {
		Function srcFunction;
		if (Utils.isNotBlank(function.getId())) {
			if (function.getId().equals(function.getParentId())) {
				return RespData.instance(RespData.SUCCESS, "父功能不能选自己!");
			}
			srcFunction = this.get(Function.class, function.getId());
			srcFunction.setName(function.getName());
			srcFunction.setDescription(function.getDescription());
			srcFunction.setParentId(function.getParentId());
			srcFunction.setState(function.getState());
			srcFunction.setCode(function.getCode());
		} else {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("code", function.getCode());
			if (this.count(Function.class, params) > 0) {
				return RespData.instance(RespData.FAIL, "功能已经存在！");
			}
			srcFunction = function;
		}
		if (Utils.isBlank(srcFunction.getParentId())) {
			srcFunction.setParentId(null);
		}
		super.save(srcFunction);
		return RespData.instance(RespData.SUCCESS, srcFunction.getId());
	}
	
	public RespData del(String[] ids) {
		if (Utils.isEmpty(ids)) {
			return RespData.instance(RespData.SUCCESS);
		} else {
			try {
				this.del(Function.class, ids);
				Map<String, Object> params = new HashMap<String, Object>();
				for (String id : ids) {
					params.put("functionId", id);
					this.del(RoleFunction.class, params);
				}
				return RespData.instance(RespData.SUCCESS);
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				return RespData.instance(RespData.FAIL);
			}
		}
	}
	
	public RespData state(String[] ids, Integer state) {
		if (Utils.isEmpty(ids)) {
			return RespData.instance(RespData.SUCCESS);
		} else {
			try {
				Map<String, Object> params = new HashMap<String, Object>(), values = new HashMap<String, Object>();
				values.put("state", state);
				this.update(Function.class, ids, values);
				for (String id : ids) {
					params.put("functionId", id);
					this.update(RoleFunction.class, params, values);
					if (Utils.isNotNull(state) && State.ACTIVE.getState() == state.intValue()) {
						enableParent(id);
					}
				}
				return RespData.instance(RespData.SUCCESS);
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				return RespData.instance(RespData.FAIL);
			}
		}
	}
	
	public List<TreeNode> tree(String roleId) {
		List<TreeNode> tree = new ArrayList<TreeNode>(); 
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("state", State.ACTIVE.getState());
		params.put("parentId", null);
		List<Function> topFunctions = this.listByProps(Function.class, params, Order.asc("name"));
		if (Utils.isEmpty(topFunctions)) {
			return tree;
		}
		TreeNode node;
		Function Function;
		int size = topFunctions.size();
		List<String> checkedFunctionIds = null;
		if (Utils.isNotBlank(roleId)) {
			params = new HashMap<String, Object>();
			params.put("roleId", roleId);
			checkedFunctionIds = this.listProp(RoleFunction.class, "functionId", String.class, params);
		}
		for (int i = 0; i < size; i++) {
			Function = topFunctions.get(i);
			node = new TreeNode(Function.getId(), Function.getName(), TreeNode.OPEN);
			if (Utils.isNotNull(checkedFunctionIds) && checkedFunctionIds.contains(Function.getId())) {
				node.setChecked(TreeNode.CHECKED);
			}
			this.listChildren(node, checkedFunctionIds);
			tree.add(node);
		}
		return tree;
	}
	
	private void listChildren(TreeNode node, List<String> checkedFunctionIds) {
		if (Utils.isNull(node)) {
			return;
		}
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("state", State.ACTIVE.getState());
		paramMap.put("parentId", node.getId());
		List<Function> children = this.listByProps(Function.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(children)) {
			return;
		}
		if (Utils.isBlank(node.getState())) {
			node.setState(TreeNode.CLOSED);
		}
		int size = children.size();
		Function child;
		TreeNode childNode;
		List<TreeNode> childNodes = new ArrayList<TreeNode>(size);
		for (int i = 0; i < size; i++) {
			child = children.get(i);
			childNode = new TreeNode(child.getId(), child.getName());
			if (Utils.isNotNull(checkedFunctionIds) && checkedFunctionIds.contains(child.getId())) {
				childNode.setChecked(TreeNode.CHECKED);
			}
			childNodes.add(childNode);
			node.setChildren(childNodes);
			listChildren(childNode, checkedFunctionIds);
		}
	}
	
	public List<FunctionNode> treeGrid() {
		List<FunctionNode> tree = new ArrayList<FunctionNode>(); 
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("parentId", null);
		List<Function> topFunctions = this.listByProps(Function.class, params, Order.asc("name"));
		if (Utils.isEmpty(topFunctions)) {
			return tree;
		}
		FunctionNode node;
		Function function;
		int size = topFunctions.size();
		for (int i = 0; i < size; i++) {
			function = topFunctions.get(i);
			node = new FunctionNode();
			node.setId(function.getId());
			node.setCode(function.getCode());
			node.setCreatedTime(function.getCreatedTime());
			node.setDescription(function.getDescription());
			node.setName(function.getName());
			node.setOperator(function.getOperator());
			node.setRowState(function.getState());
			node.setUpdatedTime(function.getUpdatedTime());
			this.listChildren(node, 1);
			tree.add(node);
		}
		return tree;
	}
	
	private void listChildren(FunctionNode node, int depth) {
		if (Utils.isNull(node)) {
			return;
		}
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("parentId", node.getId());
		List<Function> children = this.listByProps(Function.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(children)) {
			return;
		}
		if (depth >= 2) {
			node.setState("closed");
		}
		int size = children.size();
		Function child;
		FunctionNode childNode;
		List<FunctionNode> childNodes = new ArrayList<FunctionNode>(size);
		for (int i = 0; i < size; i++) {
			child = children.get(i);
			childNode = new FunctionNode();
			childNode.setId(child.getId());
			childNode.setCode(child.getCode());
			childNode.setCreatedTime(child.getCreatedTime());
			childNode.setDescription(child.getDescription());
			childNode.setName(child.getName());
			childNode.setOperator(child.getOperator());
			childNode.setRowState(child.getState());
			childNode.setUpdatedTime(child.getUpdatedTime());
			childNodes.add(childNode);
			node.setChildren(childNodes);
			listChildren(childNode, depth + 1);
		}
	}
	
	private void enableParent(String id) {
		Function cur = super.get(Function.class, id);
		if (Utils.isNotNull(cur)) {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("state", State.ACTIVE.getState());
			super.update(Function.class, new String[]{cur.getParentId()}, params);
			this.enableParent(cur.getParentId());
		}
	}
	
	private Set<String> listChildIds(String parentId) {
		Set<String> childIds = new HashSet<String>();
		List<Function> childrenList = new ArrayList<Function>();
		this.getChildren(parentId, childrenList);
		for (Function child : childrenList) {
			childIds.add(child.getId());
		}
		return childIds;
	}
	
	private void getChildren(String parentId, List<Function> childrenList) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("parentId", parentId);
		params.put("state", State.ACTIVE.getState());
		List<Function> children = this.listByProps(Function.class, params);
		if (Utils.isNotEmpty(children)) {
			for (Function child : children) {
				childrenList.add(child);
				getChildren(child.getId(), childrenList);
			}
		}
	}
}
